package scenic.toolkit;

import java.awt.geom.Point2D;

import scenic.Color;
import scenic.Graphics;
import scenic.toolkit.event.MouseEvent;
import scenic.toolkit.event.MouseListener;
import scenic.toolkit.event.MouseMotionListener;
import scenic.toolkit.event.MouseWheelEvent;

public class CScrollbar extends CComponent {
	static final public int HORIZONTAL = 0;
	static final public int VERTICAL = 1;
	
	static final private int BUTTON_SIZE = 20;
	static final private int STEP_SIZE = 20;
	static final private int MIN_KNOB_SIZE = 20;
	
	private class ScrollbarEventHandler implements MouseListener, MouseMotionListener {
		private double grabPosition;
		private double grabMousePosition;
		private boolean grabbed;
		
		private double getMousePosition(MouseEvent e) {
			if(orientation == VERTICAL)
				return e.getPosition().getY();
			else
				return e.getPosition().getX();
		}
		
		public void mouseClicked(MouseEvent e) {
		}

		public void mouseEntered(MouseEvent e) {
		}

		public void mouseExited(MouseEvent e) {
		}

		public void mousePressed(MouseEvent e) {
			double p = getMousePosition(e);
			
			e.consume();
			if(p < BUTTON_SIZE) {
				setPosition(position - STEP_SIZE);
			} else if(p > getPhysicalSize() - BUTTON_SIZE) {
				setPosition(position + STEP_SIZE);
			} else {
				grabPosition = position;
				grabMousePosition = p;
				grabbed = true;
			}
		}

		public void mouseReleased(MouseEvent e) {
			grabbed = false;
		}

		public void mouseDragged(MouseEvent e) {
			if(grabbed) {
				double p = getMousePosition(e);
				
				setPosition(grabPosition + (p - grabMousePosition) * getScaleFactor());
			}
		}

		public void mouseMoved(MouseEvent e) {
		}

		public void mouseWheelMoved(MouseWheelEvent event) {
		}		
	}	

	public int orientation;
	public double position;
	public double size;
	public double viewSize;
	
	public CScrollbar(int orientation) {
		ScrollbarEventHandler eventHandler = new ScrollbarEventHandler();
		
		this.orientation = orientation;
		addMouseListener(eventHandler);
		addMouseMotionListener(eventHandler);
	}

	private double getPhysicalSize() {
		if(orientation == VERTICAL)
			return getHeight();
		else
			return getWidth();
	}
	
	private double getScaleFactor() {
		double physicalSize = getPhysicalSize() - BUTTON_SIZE * 2 - getKnobSize();
		
		if(physicalSize == 0.0)
			return 1.0;
		return (size - viewSize) / physicalSize;
	}
	
	private double getKnobSize() {
		double s = (getPhysicalSize() - BUTTON_SIZE * 2) * (viewSize / size);
		
		if(s > getPhysicalSize() - BUTTON_SIZE * 2)
			return getPhysicalSize() - BUTTON_SIZE * 2;
		if(s < MIN_KNOB_SIZE)
			return MIN_KNOB_SIZE;
		return s;
	}
	
	public double getPosition() {
		return position;
	}
	
	public void setPosition(double position) {
		if(position > size - viewSize)
			position = size - viewSize;
		if(position < 0)
			position = 0;
		if(position != this.position) {
			this.position = position;
			invalidate();
			getParent().invalidate();
		}
	}
	
	public void setContentSize(double size) {
		this.size = size;
	}
	
	public void setViewSize(double viewSize) {
		this.viewSize = viewSize;
	}
	
	public double getSize() {
		return size;
	}
	
	public double getViewSize() {
		return viewSize;
	}
	
	public void paint(Graphics g) {
		g.clear();
		if(orientation == VERTICAL) {
			g.rectangle(0, 0, BUTTON_SIZE, getHeight());
			g.setFillColor(new Color(0.9f));
			g.fill();
			
			g.moveTo(BUTTON_SIZE * 0.5, BUTTON_SIZE * 0.2);
			g.lineTo(BUTTON_SIZE * 0.2, BUTTON_SIZE * 0.8);
			g.lineTo(BUTTON_SIZE * 0.8, BUTTON_SIZE * 0.8);
			g.close();
			g.stroke();

			g.push();
			g.translate(0, BUTTON_SIZE);
			g.rectangle(0, position / getScaleFactor(), BUTTON_SIZE, getKnobSize());
			g.setFillColor(new Color(1.0f));
			g.fillAndStroke();
			g.pop();
			
			g.translate(0, getHeight() - BUTTON_SIZE);
			g.moveTo(BUTTON_SIZE * 0.5, BUTTON_SIZE * 0.8);
			g.lineTo(BUTTON_SIZE * 0.2, BUTTON_SIZE * 0.2);
			g.lineTo(BUTTON_SIZE * 0.8, BUTTON_SIZE * 0.2);
			g.close();
			g.stroke();
		} else if(orientation == HORIZONTAL) {
			g.rectangle(0, 0, getWidth(), BUTTON_SIZE);
			g.setFillColor(new Color(0.9f));
			g.fill();
			
			g.moveTo(BUTTON_SIZE * 0.2, BUTTON_SIZE * 0.5);
			g.lineTo(BUTTON_SIZE * 0.8, BUTTON_SIZE * 0.2);
			g.lineTo(BUTTON_SIZE * 0.8, BUTTON_SIZE * 0.8);
			g.close();
			g.stroke();

			g.push();
			g.translate(BUTTON_SIZE, 0);
			g.rectangle(position / getScaleFactor(), 0, getKnobSize(), BUTTON_SIZE);
			g.setFillColor(new Color(1.0f));
			g.fillAndStroke();
			g.pop();
			
			g.translate(getWidth() - BUTTON_SIZE, 0);
			g.moveTo(BUTTON_SIZE * 0.8, BUTTON_SIZE * 0.5);
			g.lineTo(BUTTON_SIZE * 0.2, BUTTON_SIZE * 0.2);
			g.lineTo(BUTTON_SIZE * 0.2, BUTTON_SIZE * 0.8);
			g.close();
			g.stroke();			
		}
	}
	
	public Point2D getMinimumSizeFor(double width, double height) {
		return new Point2D.Double(BUTTON_SIZE, BUTTON_SIZE);
	}
}
